﻿/////////////////////////////////////////////////////////////////////////
//
// This module contains code to do a basic green screen.
////
/////////////////////////////////////////////////////////////////////////

using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Research.Kinect.Nui;
using Coding4Fun.Kinect.Wpf;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using System.Windows.Input;

namespace SkeletalTracking
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }


        //Kinect Runtime
        Runtime nui = new Runtime();


        ActiveHomeBrightnessThread activeHomeBrightness = new ActiveHomeBrightnessThread("A2", 0);


        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //Initialize to do skeletal tracking
            nui.Initialize(RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseColor);
            //nui.NuiCamera.ElevationAngle=20;

            #region TransformSmooth
            //Must set to true and set after call to Initialize
            nui.SkeletonEngine.TransformSmooth = true;

            //Use to transform and reduce jitter
            var parameters = new TransformSmoothParameters
            {
                Smoothing = 0.90f,
                Correction = 0.5f,
                Prediction = 0.5f,
                JitterRadius = 0.05f,
                MaxDeviationRadius = 0.04f
            };

            nui.SkeletonEngine.SmoothParameters = parameters;

            #endregion

            //Thread

            //add event to receive skeleton data
            nui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(nui_SkeletonFrameReady);
            nui.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_VideoFrameReady);

            
            activeHomeBrightness.turnLampOn();


            nui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color);
        }

        protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
        {
            if(e.Key.Equals(Key.Up))
                nui.NuiCamera.ElevationAngle +=5;
            else if (e.Key.Equals(Key.Down))
                nui.NuiCamera.ElevationAngle -=5;
            base.OnKeyDown(e);
        }


        void nui_VideoFrameReady(object sender, ImageFrameReadyEventArgs e)
        {
            bg.Source = e.ImageFrame.ToBitmapSource();
        }

        void nui_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {

            SkeletonFrame allSkeletons = e.SkeletonFrame;

            //get the first tracked skeleton
            SkeletonData skeleton = (from s in allSkeletons.Skeletons
                                     where s.TrackingState == SkeletonTrackingState.Tracked
                                     select s).FirstOrDefault();

            if (skeleton != null)
            {
                //set position
                SetEllipsePosition(headEllipse, skeleton.Joints[JointID.Head]);
                SetEllipsePosition(leftEllipse, skeleton.Joints[JointID.HandLeft]);
                SetEllipsePosition(rightEllipse, skeleton.Joints[JointID.HandRight]);
                ProcessSkeleton(skeleton);
            }
        }

        bool paintStarted = false;
        bool lampStarted = false;
        private void ProcessSkeleton(SkeletonData skeleton)
        {
            float headY = skeleton.Joints[JointID.Head].Position.Y;
            float headX = skeleton.Joints[JointID.Head].Position.X;
            float rHandY = skeleton.Joints[JointID.HandRight].Position.Y;
            float rHandX = skeleton.Joints[JointID.HandRight].Position.X;
            float lHandY = skeleton.Joints[JointID.HandLeft].Position.Y;
            float rKneeY = skeleton.Joints[JointID.KneeRight].Position.Y;

            if (rHandY > headY)
            {
                Process p = startProcess("mspaint.exe");
                if (p != null)
                {
                    paintStarted = true;
                    //ShowWindow(p.Handle, SW_MAXIMIZE);
                }
            }

            if (lHandY > headY)
            {
                if (!lampStarted)
                { 
                    //start the lamp??
                      
                }
                int newDim = (int)((rHandY - rKneeY) / (headY - rKneeY) * 100);
                if (newDim < 0) newDim = 0;
                if (newDim > 100) newDim = 100;
                activeHomeBrightness.setBrightness(newDim);

                //activeHome.
            }


            if (paintStarted)
            {

                setCursorPosition("Untitled - Paint", skeleton.Joints[JointID.HandLeft]);

                if (rHandY <= headY)
                    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);//left button down
                else
                    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);//left button up
            }
            if (rHandX < headX)
            {
                // check if lamp is on.  if it is, turn it off
                activeHomeBrightness.turnLampOff();
                paintStarted = false;
                mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);//left button up
                killProcess("mspaint.exe");
            }

        }

        [DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(string lpClassName,
            string lpWindowName);

        // Activate an application window.
        [DllImport("USER32.DLL")]
        public static extern bool SetForegroundWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, uint dwExtraInf);

        [DllImport("user32.dll")]
        public static extern bool SetCursorPos(int x, int y);

        [DllImport("user32.dll")]
        static extern bool ShowWindow(IntPtr hwnd, uint nCmdShow);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;        // x position of upper-left corner
            public int Top;         // y position of upper-left corner
            public int Right;       // x position of lower-right corner
            public int Bottom;      // y position of lower-right corner
        }

        private const UInt32 MOUSEEVENTF_LEFTDOWN = 0x0002;
        private const UInt32 MOUSEEVENTF_LEFTUP = 0x0004;
        private const UInt32 MOUSEEVENTF_ABSOLUTE = 0x8000;

        private const UInt32 SW_MAXIMIZE = 3;

        private void setCursorPosition(string appName, Joint j)
        {
            // Get a handle to an application window.

            IntPtr appHandle = FindWindow(null, appName);

            // Verify that process is running
            if (appHandle == (System.IntPtr.Zero))
            {
                // MessageBox.Show(appName + " is not running.");
                return;
            }

            SetForegroundWindow(appHandle);

            RECT lpRect;

            GetWindowRect(appHandle, out lpRect);

            Microsoft.Research.Kinect.Nui.Vector scaledPosition = j.ScaleTo(lpRect.Right - lpRect.Left, lpRect.Bottom - lpRect.Top).Position;
            int scaledX = (int)lpRect.Left + (int)(scaledPosition.X);
            int scaledY = (int)lpRect.Top + (int)(scaledPosition.Y);

            SetCursorPos(scaledX, scaledY);

        }


        float prevX = -1;
        float prevY = -1;
        private void SetEllipsePosition(FrameworkElement ellipse, Joint joint)
        {
            var scaledJoint = joint.ScaleTo(640, 480, .5f, .5f);
            if (joint.ID.Equals(JointID.HandRight))
            {
                if (prevX == -1 && prevY == -1)
                {
                    prevX = scaledJoint.Position.X;
                    prevY = scaledJoint.Position.Y;
                }
                else if (scaledJoint.Position.Y > prevY + 10)
                {
                    lblGesture.Content = "DOWN";
                    //killProcess("mspaint.exe");
                }
                else if (scaledJoint.Position.Y < prevY - 10)
                {
                    lblGesture.Content = "UP";

                    //startProcess("mspaint.exe");
                }
                else if (scaledJoint.Position.X > prevX + 10)
                {
                    lblGesture.Content = "RIGHT";
                }
                else if (scaledJoint.Position.X < prevX - 10)
                {
                    lblGesture.Content = "LEFT";
                }
                prevX = scaledJoint.Position.X;
                prevY = scaledJoint.Position.Y;
                //run this

            }
            Canvas.SetLeft(ellipse, scaledJoint.Position.X - 25);
            Canvas.SetTop(ellipse, scaledJoint.Position.Y - 25);

        }

        private static Process startProcess(string appName)
        {
            Boolean exists = false;
            int pId = -1;
            exists = processExists(appName, out pId);
            if (!exists)
            {
                Process p = System.Diagnostics.Process.Start(appName);
                return p;
            }
            else return null;
        }

        private static void killProcess(string appName)
        {
            Boolean exists = false;
            int pId = -1;
            exists = processExists(appName, out pId);
            if (exists)
            {
                try
                {
                    System.Diagnostics.Process.GetProcessById(pId).Kill();
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception: " + e.Message + "\n" + e.StackTrace);

                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="appName"></param>
        /// <param name="pId"></param>
        /// <returns></returns>
        private static Boolean processExists(string appName, out int pId)
        {
            bool exists = false;
            pId = -1;
            appName = appName.Substring(0, appName.IndexOf("."));
            Process[] processes =
                Process.GetProcesses();
            foreach (Process p in processes)
            {
                if (p.ProcessName.Equals(appName))
                {
                    
                    pId = p.Id;
                    exists = true;
                    break;
                }
            }
            return exists;
        }



        private void Window_Closed(object sender, EventArgs e)
        {
            //Cleanup

            activeHomeBrightness.endThread();

            nui.Uninitialize();
        }



    }
}
